package com.hotel.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

public class MybatisRedisCache implements Cache {
	private RedisTemplate<Object, Object> template;
	private String name = "";

//	将RedisTemplate放入MybatisRedisCache
	public RedisTemplate<Object, Object> getTemplate() {
		return template;
	}
	public void setTemplate(RedisTemplate<Object, Object> template) {
		this.template = template;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
//	获取缓存名称
	public String getName() {
		// TODO Auto-generated method stub
		return this.name;
	}
	@Override
//	获取本地缓存
	public Object getNativeCache() {
		// TODO Auto-generated method stub
		return this.template;
	}
	@Override
//	通过键获取值，有值，获取值。如果没有值，调取put方法
	public ValueWrapper get(Object key) {
		// TODO Auto-generated method stub
		Object object = null;
		object = template.opsForValue().get(SerializeUtil.serialize(key));
		if (object == null) {
			return null;
		}
		object = toObject((byte[]) object);
		return (object != null ? new SimpleValueWrapper(object) : null);
	}
	@Override
	public <T> T get(Object key, Class<T> type) {
		// TODO Auto-generated method stub
		Object object = null;
		object = template.opsForValue().get(SerializeUtil.serialize(key));
		if (object == null) {
			return null;
		} else {
			try {
				T t_object = (T) object;
				return t_object;
			} catch (Exception e) {
				return null;
			}
		}
	}
	@Override
//	将键值对放入缓存中
	public void put(Object key, Object value) {
		// TODO Auto-generated method stub
		final long liveTime = 86400;
		template.opsForValue().set(SerializeUtil.serialize(key), toByteArray(value));
	}
	@Override
//	从缓存中，通过键获取对应的值，如果该值不存在，将该值不存在，将值放入缓存中。
	public ValueWrapper putIfAbsent(Object key, Object value) {
		// TODO Auto-generated method stub
		Object existingValue = template.opsForValue().get(SerializeUtil.serialize(key));
		if (existingValue == null) {
			template.opsForValue().setIfAbsent(SerializeUtil.serialize(key), toByteArray(value));
			return null;
		} else {
			return new SimpleValueWrapper(existingValue);
		}
	}
	@Override
//	清除缓存
	public void evict(Object key) {
		template.delete(SerializeUtil.serialize(key));
	}
	@Override
//	清除所有缓存
	public void clear() {
		template.execute(new RedisCallback<String>() {
			public String doInRedis(RedisConnection connection) throws DataAccessException {
				connection.flushDb();
				return "ok";
			}
		});
	}
	/**
	 * 描述 : <byte[]转Object>. <br>
	 * <p>
	 * <使用方法说明>
	 * </p>
	 * @param bytes
	 * @return
	 */
//	将读取的字节数组转化为对象
	private Object toObject(byte[] bytes) {
		Object obj = null;
		try {
			ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
			ObjectInputStream ois = new ObjectInputStream(bis);
			obj = ois.readObject();
			ois.close();
			bis.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (ClassNotFoundException ex) {
			ex.printStackTrace();
		}
		return obj;
	}
	/**
	 * 描述 : <Object转byte[]>. <br>
	 * <p>
	 * <使用方法说明>
	 * </p>
	 * @param obj
	 * @return
	 */
//	将对象转化为字节数组
	private byte[] toByteArray(Object obj) {
		byte[] bytes = null;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		try {
			ObjectOutputStream oos = new ObjectOutputStream(bos);
			oos.writeObject(obj);
			oos.flush();
			bytes = bos.toByteArray();
			oos.close();
			bos.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		return bytes;
	}
}

class SerializeUtil {
	public static byte[] serialize(Object object) {
		ObjectOutputStream oos = null;
		ByteArrayOutputStream baos = null;
		try {
			// 序列化
			baos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(baos);
			oos.writeObject(object);
			byte[] bytes = baos.toByteArray();
			return bytes;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	public static Object unserialize(byte[] bytes) {
		if (bytes == null)
			return null;
		ByteArrayInputStream bais = null;
		try {
			// 反序列化
			bais = new ByteArrayInputStream(bytes);
			ObjectInputStream ois = new ObjectInputStream(bais);
			return ois.readObject();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
